﻿using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using RStein.Posterous.API;
using System.Windows.Navigation;
using RStein.PosterousReader.WP.ViewModels.ViewObjects;
using RStein.PosterousReader.WP.HostServices;
using RStein.PosterousReader.WP.Extensions;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;
using RStein.PosterousReader.Common;

namespace RStein.PosterousReader.WP.ViewModels
{
  public class PostsListViewModel : PosterousViewModelBase
  {

    public static readonly string FINAL_ADD_URL = "{0}?site={1}";
    private PostVO m_selectedPost;
    private SiteVO m_selectedSite;
    private bool m_IsSiteDownloadInProgress;
    private int m_SitePostsLoadedCounter;
    private object m_SitePostsLoadedCounterRoot;
    private ObservableCollection<SiteVO> m_sites;
    private bool m_IsPostDownloadInProgress;
    private ICommand m_AddPostComand;
    

    public PostsListViewModel(IPosterousApplication posterousApplication, INavigationService navigation)
      : base(posterousApplication, navigation, GlobalConstants.PAGE_MAIN_TITLE)
    {
      AddPostCommand = new DelegateCommand<Object>( _ => 
                                                    {
                                                      IsInvalidModel = true;
                                                      Uri fullUrl = new Uri(String.Format(FINAL_ADD_URL, GlobalConstants.PAGE_POST_ADD_URI, SelectedSite.Id), UriKind.Relative);
                                                      NavigationService.Navigate(fullUrl);
                                                    },
                                                  _ => SelectedSite != null);

      
    }

    public ICommand AddPostCommand
    {
      get
      {
        return m_AddPostComand;
      }
      
      set
      {
        m_AddPostComand = value;
        RaisePropertyChangedEvent(() => AddPostCommand);
      }
    }

    
    
    public ObservableCollection<SiteVO> Sites
    {
      get
      {
        return m_sites;
      }
      set
      {
        
        m_sites = value;
        RaisePropertyChangedEvent(() => Sites);
      }
    }

    public SiteVO SelectedSite
    {
      get
      {
        return m_selectedSite;
      }
      set
      {
        m_selectedSite = value;
        RaisePropertyChangedEvent(() => SelectedSite);
      }
    }

    public PostVO SelectedPost
    {
      get
      {
        return m_selectedPost;
      }
      set
      {
        m_selectedPost = null;
        RaisePropertyChangedEvent(() => SelectedPost);
        if (value != null)
        {
          NavigationService.Navigate(value.DetailUrl);
        }

      }
    }


    public bool IsSiteDownloadInProgress
    {
      get
      {
        return m_IsSiteDownloadInProgress;
      }

      set
      {
        m_IsSiteDownloadInProgress = value;
        RaisePropertyChangedEvent(() => IsSiteDownloadInProgress);
      }
    }

    public bool IsPostsDownloadInProgress
    {
      get
      {
        return m_IsPostDownloadInProgress;
      }

      set
      {
        m_IsPostDownloadInProgress = value;
        RaisePropertyChangedEvent(() => IsPostsDownloadInProgress);
      }
    }

    public override void Activate()
    {
      base.Activate();
      if (CanUseModel)
      {

      }
    }

    //Workaround - Interlocked methods throw NotSupportedException
    private int SitePostsLoadedCounter
    {
      get
      {
        lock (m_SitePostsLoadedCounterRoot)
        {
          return m_SitePostsLoadedCounter;
        }
      }
      set
      {
        lock (m_SitePostsLoadedCounterRoot)
        {
          m_SitePostsLoadedCounter = value;
        }
      }
    }

    protected override void DoInternalInit()
    {    
      initData();
    }

    protected override bool IsAllInitDataLoaded()
    {
      return !IsPostsDownloadInProgress && !IsSiteDownloadInProgress;
    }

    private void loadSites()
    {
      showProgress();
      var account = PosterousApplicatonService.GetOrAddCachedPosterousAccount(LastUsedUserName, LastUsedPassword); 

      account.SitesLoaded += getSiteLoadedHandler(account);

      account.LoadSitesAsync();
    }

    private void showProgress()
    {
      IsSiteDownloadInProgress = true;
      IsPostsDownloadInProgress = true;
    }

    private EventHandler<EventArgsValue<IEnumerable<IPosterousSite>>> getSiteLoadedHandler(IPosterousAccount account)
    {
      EventHandler<EventArgsValue<IEnumerable<IPosterousSite>>> siteLoadedHandler = null;
      siteLoadedHandler = (_, e) =>
                          {
                            
                              account.SitesLoaded -= siteLoadedHandler;
                              if (hasErrorInResponse(e))
                              {
                                return;
                              }

                              addSites(account);
                              selectDefaultSite(account);
                              SitePostsLoadedCounter = account.Sites.Count();
                              account.Sites
                                     .ToList()
                                     .ForEach(site =>
                                              {
                                                site.PostsLoaded += getPostsHandler(site);
                                                site.LoadAllPostsAsync();                            
                                              }
                                          );

                              IsSiteDownloadInProgress = false;
                            
                          };

      return siteLoadedHandler;
    }

    private EventHandler<EventArgsValue<IEnumerable<IPosterousPost>>> getPostsHandler(IPosterousSite site)
    {
      EventHandler<EventArgsValue<IEnumerable<IPosterousPost>>> postsLoadedHandler = null;
      postsLoadedHandler = (o, eargs) =>
                           {                              
                              
                              if (hasErrorInResponse(eargs))
                              {
                                return;
                              }

                              var siteVO = Sites
                                          .Where(siteView => siteView.Id == site.Id)
                                          .Single();

                              siteVO.Posts.Clear();
                              eargs.Value
                                  .ToList()
                                  .ForEach(post => siteVO.Posts.Add(new PostVO
                                                                              {
                                                                                SynchContext = SynchronizationContext.Current,
                                                                                Id = post.Id,
                                                                                Title = post.Title,
                                                                                DetailUrl = NavigationService.GetDetailUri(post)                                                                                
                                                                              }));


                              finalizePostsLoaded(site, postsLoadedHandler);

                          };

      return postsLoadedHandler;
    }

    private void finalizePostsLoaded(IPosterousSite site, EventHandler<EventArgsValue<IEnumerable<IPosterousPost>>> postsLoadedHandler)
    {
      if (site.TotalPosts == site.LoadedPosts)
      {
        site.PostsLoaded -= postsLoadedHandler;
        checkAllPostsFromAllSitesLoaded();
      }

    }

    private void checkAllPostsFromAllSitesLoaded()
    {
      Debug.Assert(SitePostsLoadedCounter > 0);
      
      SitePostsLoadedCounter--;      
      
      if (m_SitePostsLoadedCounter == 0)
      {
        IsPostsDownloadInProgress = false;
      }
    }

    private bool hasErrorInResponse<T>(EventArgsValue<T> e)
    {
      if (e.Exception != null)
      {
        NavigationService.GoBack();
        return true;
      }

      return false;
    }

    private void selectDefaultSite(IPosterousAccount account)
    {
      SelectedSite = Sites
                      .Where(site => account.PrimarySite.Id == site.Id)
                      .First();
    }

    private void addSites(IPosterousAccount account)
    {
      //SelectedSite = null;
      Sites.Clear();
      account.Sites
                .Select(site => new SiteVO
                  {
                    SynchContext = SynchronizationContext.Current,
                    Id = site.Id,
                    Name = site.Name
                  })
              .ToList()
              .ForEach(siteVO => Sites.Add(siteVO));


    }

    
    private void initData()
    {
      Sites = null;      
      SelectedPost = null;
      SelectedSite = null;
      Sites = new ObservableCollection<SiteVO>();      
      m_SitePostsLoadedCounterRoot = new Object();
      SitePostsLoadedCounter = 0;
      loadSites();
    }
    
  }
}